<template>
  <el-dialog v-model="dialogVisible" width="800px" :show-close="false" :close-on-click-modal="false"
    class="avatar-dialog">
    <!-- 头部 -->
    <template #header>
      <div class="dialog-header">
        <el-button link @click="handleClose">取消</el-button>
        <span class="dialog-title">选择头像</span>
        <el-button link :disabled="!selectedImage" @click="handleConfirm">完成</el-button>
      </div>
    </template>

    <!-- 主体内容 -->
    <div class="dialog-body">
      <!-- 选择图片区域 -->
      <div v-if="!selectedImage" class="upload-area">
        <div class="upload-box" @click="triggerUpload">
          <el-icon class="upload-icon">
            <Plus />
          </el-icon>
          <p class="upload-text">选择照片</p>
        </div>
        <input ref="fileInput" type="file" accept="image/*" class="hidden" @change="handleFileChange" />
      </div>

      <!-- 裁剪区域 -->
      <div v-else class="crop-container">
        <div class="crop-area">
          <vue-cropper ref="cropperRef" :src="selectedImage" :aspect-ratio="1" :view-mode="1" :guides="false"
            :center="false" :highlight="false" :background="false" :auto-crop-area="0.9" :modal="true" :movable="true"
            :zoomable="true" :crop-box-movable="true" :crop-box-resizable="false" preview=".preview-box"
            @ready="cropImage" @crop="cropImage" />
        </div>
        <div class="preview-area">
          <p class="preview-title">预览</p>
          <div class="preview-box"></div>
          <div class="tool-bar">
            <el-button-group>
              <el-button @click="handleRotate(-90)">
                <el-icon>
                  <RefreshLeft />
                </el-icon>
              </el-button>
              <el-button @click="handleRotate(90)">
                <el-icon>
                  <RefreshRight />
                </el-icon>
              </el-button>
            </el-button-group>
          </div>
        </div>
      </div>
    </div>

    <!-- 加载状态 -->
    <div v-if="uploading" class="upload-loading">
      <el-progress type="circle" :percentage="uploadProgress" />
    </div>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref, watch, nextTick } from 'vue'
import VueCropper from 'vue-cropper'
import 'vue-cropper/dist/index.css'
import { ElMessage } from 'element-plus'
import { Plus, RefreshLeft, RefreshRight } from '@element-plus/icons-vue'
import { uploadFile } from '@/api/file'

const props = defineProps<{
  modelValue: boolean
}>()

const emit = defineEmits<{
  'update:modelValue': [value: boolean]
  'success': [url: string]
}>()

const dialogVisible = ref(false)
const fileInput = ref<HTMLInputElement>()
const cropperRef = ref()
const selectedImage = ref('')
const uploading = ref(false)
const uploadProgress = ref(0)

// 监听对话框状态
watch(() => props.modelValue, (val) => {
  dialogVisible.value = val
})

watch(() => dialogVisible.value, (val) => {
  emit('update:modelValue', val)
  if (!val) {
    resetState()
  }
})

// 触发文件选择
const triggerUpload = () => {
  fileInput.value?.click()
}

// 处理文件选择
const handleFileChange = async (event: Event) => {
  const target = event.target as HTMLInputElement
  const file = target.files?.[0]

  if (!file) return

  // 验证文件类型和大小
  if (!file.type.startsWith('image/')) {
    ElMessage.error('请选择图片文件')
    return
  }

  if (file.size > 10 * 1024 * 1024) {
    ElMessage.error('图片大小不能超过10MB')
    return
  }

  try {
    // 使用 Promise 包装 FileReader
    const base64 = await new Promise<string>((resolve, reject) => {
      const reader = new FileReader()
      reader.onload = (e) => {
        if (e.target?.result) {
          resolve(e.target.result as string)
        } else {
          reject(new Error('Failed to read file'))
        }
      }
      reader.onerror = () => reject(reader.error)
      reader.readAsDataURL(file)
    })

    selectedImage.value = base64

    // 确保 cropper 组件更新
    nextTick(() => {
      if (cropperRef.value) {
        cropperRef.value.replace(base64)
      }
    })
  } catch (error) {
    console.error('Error reading file:', error)
    ElMessage.error('读取图片失败')
  }
}

// 旋转图片
const handleRotate = (deg: number) => {
  cropperRef.value?.rotate(deg)
}

// 关闭对话框
const handleClose = () => {
  dialogVisible.value = false
}

// 重置状态
const resetState = () => {
  selectedImage.value = ''
  uploading.value = false
  uploadProgress.value = 0
  if (fileInput.value) {
    fileInput.value.value = ''
  }
}

// 确认上传
const handleConfirm = async () => {
  try {
    uploading.value = true

    // 获取裁剪后的图片
    const canvas = await cropperRef.value?.getCanvas()
    if (!canvas) return

    // 转换为blob
    const blob = await new Promise<Blob>((resolve) => {
      canvas.toBlob((b: Blob | null) => {
        if (b) resolve(b)
      }, 'image/jpeg', 0.9)
    })

    // 上传文件
    const file = new File([blob], 'avatar.jpg', { type: 'image/jpeg' })
    const response = await uploadFile(file, 'avatar', (progress) => {
      uploadProgress.value = progress
    })

    emit('success', response.data.url)
    ElMessage.success('头像上传成功')
    dialogVisible.value = false
  } catch (error) {
    ElMessage.error((error as Error).message || '上传失败')
  } finally {
    uploading.value = false
  }
}

// 裁剪图片
const cropImage = () => {
  const { getCropBoxData, setCropBoxData, getData, setData } = cropperRef.value
  nextTick(() => {
    const cropBoxData = getCropBoxData()
    const data = getData()
    setCropBoxData(cropBoxData)
    setData(data)
  })
}
</script>

<style scoped>
.avatar-dialog :deep(.el-dialog) {
  border-radius: 16px;
  overflow: hidden;
}

.avatar-dialog :deep(.el-dialog__header) {
  margin: 0;
  padding: 0;
}

.dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid #f0f0f0;
}

.dialog-title {
  font-size: 16px;
  font-weight: 500;
  color: #000;
}

.dialog-body {
  padding: 0;
  height: 500px;
  position: relative;
}

.upload-area {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fafafa;
}

.upload-box {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 200px;
  height: 200px;
  border-radius: 16px;
  border: 2px dashed #e0e0e0;
  cursor: pointer;
  transition: all 0.3s;
}

.upload-box:hover {
  border-color: #000;
  background: #f5f5f5;
}

.upload-icon {
  font-size: 32px;
  color: #666;
  margin-bottom: 12px;
}

.upload-text {
  font-size: 14px;
  color: #666;
}

.crop-container {
  display: flex;
  height: 100%;
}

.crop-area {
  flex: 1;
  height: 100%;
  background: #000;
}

.preview-area {
  width: 260px;
  padding: 24px;
  border-left: 1px solid #f0f0f0;
  display: flex;
  flex-direction: column;
}

.preview-title {
  font-size: 14px;
  color: #666;
  margin-bottom: 16px;
}

.preview-box {
  width: 200px;
  height: 200px;
  border-radius: 50%;
  overflow: hidden;
  margin: 0 auto;
  background: #f5f5f5;
}

:deep(.preview-box img) {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform-origin: center;
}

.tool-bar {
  margin-top: 24px;
  display: flex;
  justify-content: center;
}

.upload-loading {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(255, 255, 255, 0.9);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 100;
}

.hidden {
  display: none;
}

:deep(.cropper-view-box),
:deep(.cropper-face) {
  border-radius: 50%;
}

:deep(.cropper-view-box) {
  outline: none;
  box-shadow: 0 0 0 1px #39f;
}

:deep(.cropper-face) {
  background: none !important;
}

:deep(.cropper-line),
:deep(.cropper-point) {
  display: none;
}
</style>
